`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Arizona State University
// Engineers: Brentton Garber, Georgii Tkachuk
// 
// Create Date: 17:28:56 04/01/2013 
// Design Name: async_fifo
// Module Name: async_fifo
// Project Name: Lab 3
// Target Devices: Xilinx Spartan6 XC6LX16-CS324 
// Tool versions: Xilinx ISE 14.2 
// Description: Stores data in order then is pushed out by the execution controller
//
// Revision: 1
// Revision 0.01 - File Created
//
//////////////////////////////////////////////////////////////////////////////////

module async_fifo
		#(SIZE = 8)
		(i_byte,
		 wclk,
		 rclk,
		 i_push,
		 i_pop,
		 reset_b,
		 o_empty,
		 o_full,
		 o_byte
		 //data
    );
//inputs 	 
input wire [7:0]i_byte;
input wire  wclk, rclk, i_push, i_pop, reset_b;
//outputs
output reg o_empty, o_full;
output reg [7:0]o_byte;
//output data;

//write and read pointers are of size lg(N)
reg [3:0]w_ptr = 3'b0;
reg [3:0]r_ptr = 3'b0;

reg full_nxt = 1'b0;
reg empty_nxt= 1'b1;

/*REGISTER FILE*/
reg [7:0]register_file[0:SIZE-1];
integer i;

assign data = (w_ptr == r_ptr);
//integer w_count = 0;
//integer r_count = 0;

//WRITE sequential logic
always @(posedge wclk or negedge reset_b)
begin
/*reset condition*/
	if (~reset_b) 
	begin
		w_ptr = 4'b0;
		o_full <= 1'b0;
		empty_nxt = 1'b1;
		for (i = 0; i <= SIZE-1; i = i + 1)
		begin
			register_file[i] = 0;
		end 
		
	end
	
	else begin
	if (w_ptr != r_ptr) begin
		o_full <= 0;
		empty_nxt = 0;
	end
	else if (~i_pop & o_full)
		o_full <= 1'b1;
	else 
		o_full <= full_nxt;
	if(i_push & ~o_full) 
	begin
		//perform a write if the queue is not full
		//if writing empty should not be full
		empty_nxt = 1'b0;
		register_file[w_ptr] = i_byte;
		
		//increment the write pointer (reset it if it reached the end of loop)
		if (w_ptr == SIZE - 1)
			w_ptr = 1'b0;
		else 
			w_ptr = w_ptr + 1;
		//if pointers meet of write the queue is full;
		if (w_ptr == r_ptr)
			o_full <= 1'b1;
		
	end
end
end

//READ sequential logic
always @(posedge rclk or negedge reset_b) begin
	if (~reset_b) begin
		//r_count <= 0;
		o_empty = 1'b1;
		r_ptr = 0;
		o_byte = 8'b0;
	end
	else begin
	if (w_ptr != r_ptr) begin
		o_empty = 0;
		
	end
	else if (~i_push & o_empty)
		o_empty = 1;
	else 
		o_empty = empty_nxt;
	if (i_pop & ~o_empty) 
	begin
			//r_count <= r_count + 1;
			full_nxt <= 1'b0;
			o_byte = register_file[r_ptr];
			if (r_ptr == SIZE - 1)
				r_ptr = 1'b0;
			else 
				r_ptr = r_ptr + 1;
			if(r_ptr == w_ptr)
				o_empty = 1'b1;
			 
	end
end
end

/*
always @(posedge i_pop or posedge i_push)begin
	if (i_pop)
		count_nxt <= count - 1;
	else if (i_push) 
		count_nxt <= count + 1;
	else 
		count_nxt <= count;
		
end
*/



/*
always @(i_push or i_pop) begin
	if (~reset_b) begin 
		count = 0;
		o_full = 0;
		o_empty = 1;
	end
	else begin
	//adjust count if read or write
	if(i_push && (w_ptr) 
		
	else if (i_pop && ~o_empty)
		count = count - 1;
	
	if (count == size-1) begin
		o_full = 1;
		o_empty =0;
	end
	else if (count == 0) begin
		o_empty = 1;
		o_full = 0;
	end
	else begin 
		o_full = 0;
		o_empty = 0;
	end
	end
end	
*/	
endmodule
